using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Objects;
using System.Data.SqlClient;
using System.Linq;
using Microsoft.Data.Extensions;

using MvcCms.Data;
using Devart.Data.PostgreSql;


namespace MvcCmsForum.Data
{
    public class EntityForumRepository : IForumRepository
    {
        #region Constructors
        private readonly MvcCmsEntities _entities;
        private readonly IEntitiesProvider _entitiesProvider;

        public EntityForumRepository(IEntitiesProvider entitiesProvider)
        {
            _entities = entitiesProvider.GetEntityContext();
            _entitiesProvider = entitiesProvider;
        }
        #endregion

        #region Forum methods

        public Forum CreateForum(Forum forumToCreate)
        {
            _entities.ForumSet.AddObject(forumToCreate);
            _entities.SaveChanges();
            return forumToCreate;
        }

        public Forum GetForum(string path)
        {
            return (from s in _entities.ForumSet
                    .Include("Portal")
                    where s.Path.ToLower() == path.ToLower()
                    orderby s.Importance
                    select s).FirstOrDefault();
        }
        public Forum GetForum(int id)
        {
            return (from s in _entities.ForumSet
                    .Include("Portal")
                    where s.ForumID == id
                    select s).FirstOrDefault();
        }

        private IEnumerable<Forum> ListForums()
        {
            return (from c in _entities.ForumSet
                    orderby c.Importance
                    select c).ToList();
        }

        public IEnumerable<Forum> ListForums(int portalId)
        {
            return (from c in _entities.ForumSet
                    where c.Portal.PortalID == portalId
                    orderby c.Importance
                    select c).ToList();
        }

        public Forum EditForum(Forum forumToEdit)
        {
            Forum originalForum = GetForum(forumToEdit.ForumID);

            // Save changes
            _entities.ForumSet.ApplyCurrentValues(forumToEdit);
            _entities.SaveChanges();
            return forumToEdit;
        }

        public void DeleteForum(Forum forumToDelete)
        {
            DbCommand command = _entities.CreateStoreCommand("delete_Forum",
                 CommandType.StoredProcedure,
                 new PgSqlParameter("_ForumID", forumToDelete.ForumID)
                );
            using (command.Connection.CreateConnectionScope())
            {
                command.ExecuteReader();
                var forums = ListForums();
                _entitiesProvider.Refresh(_entities, RefreshMode.StoreWins, forums);
            }
        }

        #endregion

        #region Post methods

        public int CreatePost(Post postToCreate)
        {
            bool resetpath = false;
            if (postToCreate.PostID == 0 && postToCreate.ThreadParentPost != null)
            {
                resetpath = true;
            }
            _entities.PostSet.AddObject(postToCreate);
            _entities.SaveChanges();

            if (resetpath)
            {
                postToCreate.Path = postToCreate.Path + "-" + postToCreate.PostID;
                EditPost(postToCreate);
            }

            return postToCreate.PostID;

        }
        public Post GetPost(string path, int forumId)
        {
            return (from s in _entities.PostSet
                   .Include("ThreadUser")
                   .Include("ReplyUser")
                   .Include("Forum")
                   .Include("ThreadParentPost")
                    where s.Path.ToLower() == path.ToLower() &&
                    s.Forum.ForumID == forumId
                    select s).FirstOrDefault();
        }
        public Post GetPost(int id)
        {
            return (from s in _entities.PostSet
                   .Include("ThreadUser")
                   .Include("ReplyUser")
                   .Include("Forum")
                   .Include("ThreadParentPost")
                    where s.PostID == id
                    select s).FirstOrDefault();
        }
        public IEnumerable<Post> ListReplies(int threadId)
        {
            return (from c in _entities.PostSet
                   .Include("ThreadUser")
                   .Include("ReplyUser")
                   .Include("Replies")
                    where c.ThreadParentPost.PostID == threadId
                    orderby c.AddedDate
                    select c);
        }
        public Post GetLastReply(int threadId)
        {
            return (from c in _entities.PostSet
                    where c.ThreadParentPost.PostID == threadId
                    orderby c.ReplyNumber descending 
                    select c).First();
        }
        public IEnumerable<Post> ListUserPosts(Guid userId)
        {
            return (from c in _entities.PostSet
                   .Include("Forum")
                   .Include("ThreadParentPost")
                    where c.ThreadUser.UserID == userId &&
                    c.ThreadParentPost == null
                    orderby c.LastPostDate descending
                    select c).Take(10).ToList();
        }

        public IEnumerable<Post> ListPortalForumsPosts(int portalId)
        {
            return (from c in _entities.PostSet
                   .Include("Forum")
                   .Include("ThreadUser")
                   .Include("ReplyUser")
                   .Include("ThreadParentPost")
                    where c.Forum.Portal.PortalID == portalId &&
                    c.ThreadParentPost == null
                    orderby c.LastPostDate descending
                    select c).Take(10).ToList();
        }
        public IEnumerable<Post> ListPosts(int forumId)
        {
            return (from c in _entities.PostSet
                   .Include("ThreadUser")
                   .Include("ReplyUser")
                   .Include("ThreadParentPost")
                    where c.Forum.ForumID == forumId
                    orderby c.AddedDate descending
                    select c).ToList();
        }
        private IEnumerable<Post> ListPosts()
        {
            return (from c in _entities.PostSet
                    orderby c.LastPostDate descending
                    select c).ToList();
        }
        public Post EditPost(Post postToEdit)
        {
            // Save changes
            _entities.PostSet.ApplyCurrentValues(postToEdit);
            _entities.SaveChanges();
            return postToEdit;
        }
        public void DeletePost(Post postToDelete)
        {
            DbCommand command = _entities.CreateStoreCommand("delete_Post",
                 CommandType.StoredProcedure,
                 new PgSqlParameter("_PostID", postToDelete.PostID)
                );
            using (command.Connection.CreateConnectionScope())
            {
                command.ExecuteReader();
            }

        }
        #endregion

        #region Vote methods

        public Vote GetVote(int postId, Guid userId)
        {
            return (from s in _entities.VoteSet
                    where s.PostID == postId &&
                            s.UserID == userId
                    select s).FirstOrDefault();
        }
        public int GetUserVoteTotal(Guid userId)
        {
            try
            {
                return (from s in _entities.VoteSet
                        where s.UserID == userId
                        select s).Sum(c => c.Direction);
            }
            catch
            {
                return 0;
            }
        }
        #endregion

    }
}